package com.yugao.fintech.antelope.system.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.yugao.fintech.antelope.auth.AuthApi;
import com.yugao.fintech.antelope.base.utils.ExcelContentType;
import com.yugao.fintech.antelope.base.utils.ExcelUtils;
import com.yugao.fintech.antelope.base.log.LogTag;
import com.yugao.fintech.antelope.base.log.OperateLog;
import com.yugao.fintech.antelope.base.log.enums.BusinessType;
import com.yugao.fintech.antelope.base.ram.ActionType;
import com.yugao.fintech.antelope.base.ram.RamResource;
import com.yugao.fintech.antelope.system.assembly.SysRoleAssembly;
import com.yugao.fintech.antelope.system.model.entity.SysMenuRule;
import com.yugao.fintech.antelope.system.model.entity.SysRole;
import com.yugao.fintech.antelope.system.model.entity.SysRoleMenu;
import com.yugao.fintech.antelope.system.model.rqrs.ram.ResourcePermResp;
import com.yugao.fintech.antelope.system.model.rqrs.ram.ResourcePermSaveReq;
import com.yugao.fintech.antelope.system.service.*;
import com.yugao.fintech.framework.assistant.utils.StringUtils;
import com.yugao.fintech.framework.core.response.Resp;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.annotation.Validated;

import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Map;


@Tag(name = "角色管理")
@LogTag(name = "角色管理")
@RestController
@RequestMapping("/role")
public class SysRoleController {
    @Autowired
    private SysRoleService roleService;

    @Autowired
    private SysMenuDataRuleService sysMenuDataRuleService;

    @Autowired
    private SysRolePermissionService sysRolePermissionService;

    @Autowired
    private SysUserService sysUserService;

    @Autowired
    private AuthApi authApi;
    @Autowired
    private AuthorizeService authorizeService;
    @Autowired
    private SysRoleAssembly sysRoleAssembly;

    @GetMapping("/page")
    @RamResource(action = "sys:role:query", name = "查询角色", type = ActionType.READ)
    public Resp<IPage<RoleResp>> page(RolePageReq query) {
        IPage<RoleResp> list = roleService.pageRole(query);
        return Resp.ok(list);
    }

    @GetMapping("/listAllRole")
    @RamResource(action = "sys:role:query", name = "查询角色", type = ActionType.READ)
    public Resp<List<RoleResp>> listAllRole() {
        List<RoleResp> list = roleService.listAllRole();
        return Resp.ok(list);
    }

    @OperateLog(summary = "导出角色", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    @RamResource(action = "sys:role:export", name = "导出角色", type = ActionType.READ)
    public void export(HttpServletResponse response, RoleListReq query) throws Exception {
        List<RoleResp> list = roleService.listRole(query);
        ExcelUtils.exportExcel(response, ExcelContentType.XLS, "角色数据.xls", RoleResp.class, list);
    }

    @Operation(summary = "根据角色编号获取详细信息")
    @GetMapping(value = "/get")
    @RamResource(action = "sys:role:query", name = "查询角色", type = ActionType.READ)
    public Resp<SysRole> get(@RequestParam(value = "roleId") Long roleId) {
        return Resp.ok(roleService.getRoleById(roleId));
    }

    @Operation(summary = "新增角色")
    @OperateLog(summary = "新增角色", businessType = BusinessType.INSERT)
    @PostMapping("/save")
    @RamResource(action = "sys:role:save", name = "保存角色", type = ActionType.WRITE)
    public Resp<?> saveRole(@Validated @RequestBody RoleSaveReq req) {
        roleService.saveRole(req);
        return Resp.ok() ;
    }

    @Operation(summary = "修改保存角色")
    @OperateLog(summary = "更新角色", businessType = BusinessType.UPDATE)
    @PostMapping("/update")
    @RamResource(action = "sys:role:update", name = "更新角色", type = ActionType.WRITE)
    public Resp<Boolean> update(@Validated @RequestBody RoleUpdateReq role) {
        boolean ret = roleService.updateRoleById(role);
        return Resp.ok(ret);
    }

    @Operation(summary = "修改保存数据权限")
    @OperateLog(summary = "更新角色菜单权限", businessType = BusinessType.UPDATE)
    @PostMapping("/updateDataScope")
    @RamResource(action = "sys:role:updateDataScope", name = "更新角色数据权限", type = ActionType.WRITE)
    public Resp<?> updateDataScope(@RequestBody RoleDataScopeUpdateReq rq) {
        SysRole role = sysRoleAssembly.toRole(rq);
        return roleService.authDataScope(role) > 0 ? Resp.ok() : Resp.fail("更新角色权限失败");
    }

    @Operation(summary = "状态修改")
    @OperateLog(summary = "修改状态", businessType = BusinessType.UPDATE)
    @PutMapping("/changeStatus")
    public Resp<?> changeStatus(@RequestBody SysRole role) {
        roleService.checkRoleAllowed(role);
        return roleService.updateRoleStatus(role) > 0 ? Resp.ok() : Resp.fail("更新失败");
    }

    @Operation(summary = "删除角色")
    @OperateLog(summary = "删除角色", businessType = BusinessType.DELETE)
    @DeleteMapping("/delete")
    @RamResource(action = "sys:role:delete", name = "删除角色", type = ActionType.WRITE)
    public Resp<?> remove(@RequestParam(value = "id") String roleId) {
        Long[] roleIds = new Long[] {Long.parseLong(roleId)};
        return roleService.deleteRoleByIds(roleIds) ? Resp.ok() : Resp.fail("删除失败");
    }

    @Operation(summary = "分配角色权限")
    @OperateLog(summary = "分配角色权限", businessType = BusinessType.INSERT)
    @PostMapping("/addRolePermission")
    @RamResource(action = "sys:role:addRolePermission", name = "为角色分配权限", type = ActionType.WRITE)
    public Resp<?> addRolePermission(@RequestBody AssignRolePermissionReq req) {
        sysRolePermissionService.addRolePermission(req);
        List<Long> userIds = sysUserService.listUserIdsByRoleId(req.getRoleId());
        // 由于角色权限已经被更改, 则清空所有token, 使所有用户重新登录
        authApi.removeAccessTokenByUserIds(userIds);
        return Resp.ok();
    }


    @Operation(summary = "获取角色权限")
    @GetMapping("/listRolePermission")
    @RamResource(action = "sys:role:listRolePermission", name = "查询角色权限", type = ActionType.READ)
    public Resp<List<RolePermResp>> listRolePermission(@NotEmpty(message = "请选择角色") @RequestParam(name = "roleId") Long roleId) {
        return Resp.ok(sysRolePermissionService.listRolePermission(roleId));
    }

    @Operation(summary = "查询数据规则数据")
    @GetMapping(value = "/listDataRule")
    @RamResource(action = "sys:role:listDataRule", name = "查询角色权限的数据规则", type = ActionType.READ)
    public Resp<RolePermissionDataRuleListReq> listDataRule(@RequestParam("permissionId") String permissionId,
                                                            @RequestParam("roleId") String roleId) {
        List<SysMenuRule> sysMenuRulePOPOS = sysMenuDataRuleService.listPermissionRule(permissionId);
        if (sysMenuRulePOPOS.isEmpty()) {
            return Resp.fail("未找到权限配置信息");
        }

        RolePermissionDataRuleListReq result = new RolePermissionDataRuleListReq();
        result.setDataRules(sysMenuRulePOPOS);

        SysRoleMenu sysRoleMenu = roleService.getRoleMenu(permissionId, roleId);
        if (sysRoleMenu != null) {
            String drChecked = sysRoleMenu.getDataRuleIds();
            if(StringUtils.isNotEmpty(drChecked)) {
                result.setDrChecked(drChecked.endsWith(",") ? drChecked.substring(0, drChecked.length()-1) : drChecked);
            }
        }

        return Resp.ok(result);
    }

    @Operation(summary = "保存数据规则")
    @OperateLog(summary = "保存角色数据权限规则", businessType = BusinessType.INSERT)
    @PostMapping(value = "/saveDataRule")
    @RamResource(action = "sys:role:saveDataRule", name = "保存角色权限的数据规则", type = ActionType.WRITE)
    public Resp<?> saveDataRule(@RequestBody RolePermissionDataRuleSaveReq req) {
        roleService.saveRoleMenu(req);
        return Resp.ok();
    }


    @Operation(summary = "添加用户")
    @OperateLog(summary = "添加用户", businessType = BusinessType.INSERT)
    @PostMapping("/addUser")
    @RamResource(action = "sys:role:addUser", name = "为角色分配用户", type = ActionType.WRITE)
    public Resp<?> addUser(@RequestBody @Validated AssignRoleUserReq req) {
        roleService.addUser(req);
        return Resp.ok();
    }

    @Operation(summary = "删除用户")
    @OperateLog(summary = "删除用户", businessType = BusinessType.DELETE)
    @DeleteMapping("/deleteUser")
    @RamResource(action = "sys:role:deleteUser", name = "删除角色关联的用户", type = ActionType.WRITE)
    public Resp<?> deleteUser(@RequestParam(value = "userId") @NotNull(message = "请选择用户") Long userId,
                               @RequestParam(value = "roleId") @NotNull(message = "请选择角色") Long roleId) {
        roleService.deleteUser(userId, roleId);
        return Resp.ok();
    }

    @Operation(summary = "删除用户")
    @RamResource(action = "sys:role:deleteUser", name = "删除角色关联的用户", type = ActionType.WRITE)
    @OperateLog(summary = "批量删除用户", businessType = BusinessType.DELETE)
    @DeleteMapping("/deleteBatchUser")
    public Resp<?> deleteBatchUser(@RequestParam(value = "userIds") @NotEmpty(message = "请选择用户") String userIdsStr,
                               @RequestParam(value = "roleId") @NotNull(message = "请选择角色") Long roleId) {
        roleService.deleteBatchUser(StringUtils.toList(userIdsStr, ",", Long.class), roleId);
        return Resp.ok();
    }

    /**
     * 菜单中的按钮类型, 就相当于接口资源
     */
    @Operation(summary = "获取角色关联的接口资源")
    @RamResource(action = "sys:role:listApiResource", name = "获取角色关联的接口资源", type = ActionType.READ)
    @GetMapping("/listApiResource")
    public Resp<List<ResourcePermResp>> listApiResource(@RequestParam(value = "roleId") @NotNull(message = "请选择角色") Long roleId) {
        List<ResourcePermResp>  respList = authorizeService.listApiResource(roleId);
        return Resp.ok(respList);
    }

    @Operation(summary = "保存角色关联的接口资源")
    @RamResource(action = "sys:role:saveApiResource", name = "保存角色关联的接口资源", type = ActionType.WRITE)
    @PostMapping("/saveApiResource")
    public Resp<?> saveApiResource(@Validated @RequestBody ResourcePermSaveReq req) {
        authorizeService.saveApiResource(req);
        return Resp.ok();
    }

    /**
     * 获取角色权限(忽略租户)
     * @param roleIds 角色id
     * @return key: 模块名, key: 可访问的资源路径集合
     */
    @GetMapping("/listAssignUrl")
    public Resp<Map<String, List<String>>> listAssignRoleUrl(@RequestParam("roleIds") List<Long> roleIds) {
        return Resp.ok(authorizeService.listAssignRoleUrl(roleIds));
    }
}